package ace.cmp.security.core.impl.matcher;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

/**
 * @author caspar
 * @date 2023/3/15 9:16 安全认证与授权接口匹配器, 获取注解 {@link PreAuthorize} {@link PostAuthorize} 关联的mvc patterns path
 */
public class SecurityAuthMatcherImpl implements SecurityAuthMatcher {
  private final RequestMappingHandlerMapping handlerMapping;

  public SecurityAuthMatcherImpl(RequestMappingHandlerMapping handlerMapping) {
    this.handlerMapping = handlerMapping;
  }

  /**
   * 获取注解 {@link PreAuthorize} {@link PostAuthorize} 关联的mvc patterns path
   */
  @Override
  public List<String> getAuthUris() {
    List<String> authorizeUrls = new ArrayList<>();
    Map<RequestMappingInfo, HandlerMethod> handlerMethods = handlerMapping.getHandlerMethods();

    handlerMethods
        .entrySet()
        .forEach(
            entry -> {
              HandlerMethod handlerMethod = entry.getValue();
              RequestMappingInfo requestMappingInfo = entry.getKey();

              List<Class> classes = Arrays.asList(PreAuthorize.class, PostAuthorize.class);

              for (Class cls : classes) {
                // 获取方法上边的注解
                Object method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), cls);
                // 获取类上边的注解
                Object controller =
                    AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), cls);
                if (method != null || controller != null) {
                  authorizeUrls.addAll(requestMappingInfo.getPatternValues());
                  break;
                }
              }
            });

    return authorizeUrls;
  }
}
